package com.xuecheng.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.learning.model.dto.CourseRecordDTO;
import com.xuecheng.api.learning.model.vo.ResourceUrlModel;
import com.xuecheng.api.media.MediaApi;
import com.xuecheng.api.search.model.dto.CoursePubIndexDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseChargeEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.JsonUtil;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.learning.agent.MediaApiAgent;
import com.xuecheng.learning.agent.SearchApiAgent;
import com.xuecheng.learning.common.constant.LearningErrorCode;
import com.xuecheng.learning.convert.CourseRecordConvert;
import com.xuecheng.learning.entity.CourseRecord;
import com.xuecheng.learning.mapper.CourseRecordMapper;
import com.xuecheng.learning.service.CourseRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 选课记录 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseRecordServiceImpl extends ServiceImpl<CourseRecordMapper, CourseRecord> implements CourseRecordService {

    /**
     * 1.判断关键数据
     * coursePubId  userName
     * 2.根据数据查询选课记录
     * 有数据,转为dto返回
     * 无数据,返回空
     * <p>
     * PS：userName是通过UAASecurityUtils来获得，获得的来源是在请求令牌中拿到。
     * 请求令牌只有用户的userName，并没有userId值。
     */
    public CourseRecordDTO getCourseRecordByCoursePuId(Long coursePubId, String userName) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(coursePubId) || StringUtil.isEmpty(userName)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.根据数据查询选课记录
        LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);
        queryWrapper.eq(CourseRecord::getUserName, userName);

        CourseRecord courseRecord = this.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(courseRecord)) {
            //无数据,返回空
            return null;
        } else {
            //有数据,转为dto返回
            CourseRecordDTO courseRecordDTO = CourseRecordConvert.INSTANCE.entity2dto(courseRecord);
            return courseRecordDTO;
        }
    }

    @Autowired
    private SearchApiAgent searchApiAgent;

    /**
     * 1.判断关键数据
     * username  coursePubId (用户对课程是否有学习记录)
     * 2.获得课程发布数据并判断
     * 判断课程是否收费-->学习记录
     * 3.添加或修改课程学习记录
     * 先查询课程学习记录是否存在
     * 存在--修改
     * 修改用户学习进度
     * 不存在--添加
     * 4.po转dto返回
     */
    @Transactional
    public CourseRecordDTO createOrModifyRecord(CourseRecordDTO dto) {
        //1.判断关键数据
        String userName = dto.getUserName();
        Long coursePubId = dto.getCoursePubId();
        if (StringUtil.isEmpty(userName) || ObjectUtils.isEmpty(coursePubId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.获得课程发布数据并判断
        RestResponse<CoursePubIndexDTO> response = searchApiAgent.getCoursePubIndexById4s(coursePubId);
        if (!(response.isSuccessful())) {
            ExceptionCast.cast(LearningErrorCode.E_202202);
        }
        CoursePubIndexDTO coursePubIndexDTO = response.getResult();
        if (ObjectUtils.isEmpty(coursePubIndexDTO)) {
            ExceptionCast.cast(LearningErrorCode.E_202202);
        }

        //判断课程是否收费-->学习记录
        /*
         * 根据业务需求：
         *       如果课程是收费课程的话，学员才会有学习记录
         *       根据项目经理的分析，其实际意义有逻辑错误
         *    项目要求：不管是收费课程还是免费课程，学员都是有学习记录
         *    关键数据：CourseRecord--paid（是否支付）
         *       收费课程：paid
         *           paid--1 ：课程已支付
         *           paid--0 ： 课程未支付
         *       免费课程：paid
         *           paid ： null
         * */
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(coursePubIndexDTO.getCharge())) {
            dto.setPaid(CourseRecord.IS_PAID);
        }
        //3.添加或修改课程学习记录
        //先查询课程学习记录是否存在
        LambdaQueryWrapper<CourseRecord> recordQueryWrapper = new LambdaQueryWrapper<>();
        recordQueryWrapper.eq(CourseRecord::getUserName, userName);
        recordQueryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);

        CourseRecord courseRecord = this.getOne(recordQueryWrapper);
        if (ObjectUtils.isEmpty(courseRecord)) {
            //不存在--添加
            courseRecord = new CourseRecord();
            courseRecord.setId(null);
            //用户名
            courseRecord.setUserName(userName);
            //公司id
            courseRecord.setCompanyId(coursePubIndexDTO.getCompanyId());
            //课程基本信息id
            courseRecord.setCourseId(coursePubIndexDTO.getCourseId());
            //课程发布id
            courseRecord.setCoursePubId(coursePubId);
            //课程名称
            courseRecord.setCoursePubName(coursePubIndexDTO.getName());
            //教学模式
            courseRecord.setTeachmode(coursePubIndexDTO.getTeachmode());

            //3.2新添加的课程记录要默认赋值为本课程的第一章节的第一小节
            //3.2.1获得课程大纲
            String teachplanJsonStr = coursePubIndexDTO.getTeachplan();
            // 课程大纲的树形结构（三级课程计划），获得数据为一级课程计划数据
            TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJsonStr, TeachplanDTO.class);
            //3.2.2获得二级课程计划第一个章节内容
            List<TeachplanDTO> secTeachPlanTreeNodes = teachplanDTO.getTeachPlanTreeNodes();
            if (ObjectUtils.isEmpty(secTeachPlanTreeNodes)) {
                ExceptionCast.cast(LearningErrorCode.E_202205);
            }
            TeachplanDTO secTeachplan = secTeachPlanTreeNodes.get(0);
            //3.3.3获得三级课程计划第一个小节
            List<TeachplanDTO> thridTeachPlanTreeNodes = secTeachplan.getTeachPlanTreeNodes();
            if (ObjectUtils.isEmpty(thridTeachPlanTreeNodes)) {
                ExceptionCast.cast(LearningErrorCode.E_202205);
            }
            TeachplanDTO thirdTeachplan = thridTeachPlanTreeNodes.get(0);

            courseRecord.setTeachplanId(thirdTeachplan.getTeachPlanId());
            courseRecord.setTeachplanName(thirdTeachplan.getPname());
            //支付记录
            courseRecord.setPaid(dto.getPaid());

            boolean save = this.save(courseRecord);
            if (!save) {
                ExceptionCast.cast(LearningErrorCode.E_202204);
            }
        } else {
            //存在--修改
            //修改用户学习进度
            LambdaUpdateWrapper<CourseRecord> recordUpdateWrapper = new LambdaUpdateWrapper<>();
            recordUpdateWrapper.set(CourseRecord::getTeachplanId, dto.getTeachplanId());
            recordUpdateWrapper.set(CourseRecord::getTeachplanName, dto.getTeachplanName());
            recordUpdateWrapper.set(CourseRecord::getChangeDate, LocalDateTime.now());
            recordUpdateWrapper.eq(CourseRecord::getId, courseRecord.getId());

            boolean update = this.update(recordUpdateWrapper);
            if (!update) {
                ExceptionCast.cast(LearningErrorCode.E_202204);
            }
        }
        //4.po转dto返回
        CourseRecordDTO courseRecordDTO = CourseRecordConvert.INSTANCE.entity2dto(courseRecord);
        return courseRecordDTO;
    }

    @Autowired
    private MediaApiAgent mediaApiAgent;

    /**
     * 1.判断关键数据
     * coursePubId  teachplanId  mediaId  userName
     * 2.根据coursePubId获得课程发布数据
     * 判断课程发布数据是否存在
     * 2.1获得课程计划数据根据 teachplanId 判断对应的三级课程计划是否存在
     * 3.根据课程的charge来判断是否有权限获得资源路径地址
     * 3.1如果收费
     * 判断此小节(三级课程计划)是否收费--->免费,返回资源地址   (收费课程某个小节有可能会是免费的)
     * --->不免费,根据学习记录,paid=1
     * 3.2如果免费-->返回资源路径地址
     * 4.根据mediaId 获得媒资信息并判断是否存在
     * 5.将数据封装返回
     */
    public ResourceUrlModel playUrl(Long coursePubId, Long teachplanId, Long mediaId, String userName) {
        //创建封装结果对象
        ResourceUrlModel resourceUrlModel = new ResourceUrlModel();
        //1.判断关键数据
        if (ObjectUtils.isEmpty(coursePubId) || ObjectUtils.isEmpty(teachplanId) ||
                ObjectUtils.isEmpty(mediaId) || StringUtil.isEmpty(userName)) {
            resourceUrlModel.wrong(CommonErrorCode.E_100101);
            return resourceUrlModel;
        }
        //2.根据coursePubId获得课程发布数据
        RestResponse<CoursePubIndexDTO> pubResponse = searchApiAgent.getCoursePubIndexById4s(coursePubId);
        //判断课程发布数据是否存在
        if (!pubResponse.isSuccessful()) {
            resourceUrlModel.wrong(LearningErrorCode.E_202202);
            return resourceUrlModel;
        }
        CoursePubIndexDTO coursePubIndexDTO = pubResponse.getResult();
        if (ObjectUtils.isEmpty(coursePubIndexDTO)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202202);
            return resourceUrlModel;
        }
        //2.1获得课程计划数据  根据 teachplanId 判断对应的三级课程计划是否存在
        String teachplanJsonStr = coursePubIndexDTO.getTeachplan();
        TeachplanDTO teachplanDTO = JsonUtil.jsonToObject(teachplanJsonStr, TeachplanDTO.class);
        if (ObjectUtils.isEmpty(teachplanDTO)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202205);
            return resourceUrlModel;
        }

        //获得二级课程计划集合
        List<TeachplanDTO> secTeachPlanTreeNodes = teachplanDTO.getTeachPlanTreeNodes();
        if (CollectionUtils.isEmpty(secTeachPlanTreeNodes)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202205);
            return resourceUrlModel;
        }
        //声明一个三级课程计划变量
        TeachplanDTO thirdTeachplanDTO = null;

        for (TeachplanDTO secTeachPlanTreeNode : secTeachPlanTreeNodes) {

            if (!(ObjectUtils.isEmpty(thirdTeachplanDTO))) {
                break;
            }
            //获得二级中三级课程计划集合
            List<TeachplanDTO> thirdTeachPlanTreeNodes = secTeachPlanTreeNode.getTeachPlanTreeNodes();
            // 有些课程的课程计划是只有二级课程计划（原因为了课程的营销）
            if (CollectionUtils.isEmpty(thirdTeachPlanTreeNodes)) {
                continue;
            }
            //从三级课程计划查找用户所选择的 teachplanId 对应的课程
            for (TeachplanDTO thirdTeachPlanTreeNode : thirdTeachPlanTreeNodes) {
                if (ObjectUtils.nullSafeEquals(teachplanId, thirdTeachPlanTreeNode.getTeachPlanId())) {
                    thirdTeachplanDTO = thirdTeachPlanTreeNode;
                    break;
                }
            }
        }
        if (ObjectUtils.isEmpty(thirdTeachplanDTO)) {
            resourceUrlModel.wrong(LearningErrorCode.E_202205);
            return resourceUrlModel;
        }

        //3.根据课程的charge来判断是否有权限获得资源路径地址
        Boolean isPaid = false;
        // 课程计划：isPreview = 1--免费 ， isPreview = 0--收费
        if (CourseChargeEnum.CHARGE_YES.getCode().equals(coursePubIndexDTO.getCharge())) {
            //3.1如果收费
            //判断此小节(三级课程计划)是否收费--->免费,返回资源地址   (收费课程某个小节有可能会是免费的)
            if (CommonEnum.USING_FLAG.getCode().equals(thirdTeachplanDTO.getIsPreview())) {
                isPaid = true;
            }

            //--->不免费,根据学习记录,paid=1
            if (!isPaid) {
                LambdaQueryWrapper<CourseRecord> recordQueryWrapper = new LambdaQueryWrapper<>();
                recordQueryWrapper.eq(CourseRecord::getUserName, userName);
                recordQueryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);

                CourseRecord courseRecord = this.getOne(recordQueryWrapper);
                if (!(ObjectUtils.isEmpty(courseRecord))) {
                    if (CourseRecord.IS_PAID == courseRecord.getPaid()) {
                        isPaid = true;
                    }
                }
            }

        } else {
            //3.2如果免费-->返回资源路径地址
            isPaid = true;
        }
        if (isPaid) {
            //4.根据mediaId 获得媒资信息并判断是否存在
            RestResponse<ResourceUrlModel> mediaResponse = mediaApiAgent.getMediaUrl(mediaId);
            if (!mediaResponse.isSuccessful()) {
                resourceUrlModel.wrong(LearningErrorCode.E_200101);
            }
            ResourceUrlModel mediaurlModel = mediaResponse.getResult();
            //5.将数据封装返回result = {ResourceUrlModel@15835} "ResourceUrlModel(pushUrl=null, playUrl=null, state=0, message=null)"
            return mediaurlModel;
        }

        // 返回没有找到媒资信息的内容
        resourceUrlModel.wrong(LearningErrorCode.E_202206);
        return resourceUrlModel;
    }


    /**
     * 1.判断关键数据
     * pageNo  pageSize  userName
     * 2.根据 userName 创建查询条件
     * 3.创建分页数据
     * 4.查询并将po转为dto封装返回
     */
    public PageVO<CourseRecordDTO> queryCourseRecordList(PageRequestParams params, String userName) {
        //1.判断关键数据
        if (StringUtil.isEmpty(userName)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }

        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();
        if (pageNo < 1) {
            pageNo = PageRequestParams.DEFAULT_PAGE_NUM;
        }
        if (pageSize < 1) {
            pageSize = PageRequestParams.DEFAULT_PAGE_SIZE;
        }
        //2.根据 userName 创建查询条件
        LambdaQueryWrapper<CourseRecord> recordQueryWrapper = new LambdaQueryWrapper<>();
        recordQueryWrapper.eq(CourseRecord::getUserName, userName);

        //按学习时间进行排序(每次学习会修改时间)
        recordQueryWrapper.orderByDesc(CourseRecord::getChangeDate);
        //3.创建分页数据
        Page<CourseRecord> page = new Page<>(pageNo, pageSize);

        //4.查询并将po转为dto封装返回
        Page<CourseRecord> pageResult = this.page(page, recordQueryWrapper);

        long total = pageResult.getTotal();
        List<CourseRecord> records = pageResult.getRecords();

        //pos-->dtos
        List<CourseRecordDTO> courseRecordDTOS = CourseRecordConvert.INSTANCE.entitys2dtos(records);

        //封装数据并返回
        PageVO<CourseRecordDTO> pageVO = new PageVO<>(courseRecordDTOS, total, pageNo, pageSize);

        return pageVO;
    }

    /**
     * 1.判断关键数据
     * coursePubId  companyId
     * 2.根据 coursePubId  companyId 查询课程记录
     * 3.po转为dto返回
     */
    public List<CourseRecordDTO> recentLearnedUsers(Long coursePubId, Long companyId) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(coursePubId) || ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //2.根据 coursePubId  companyId 查询课程记录
        LambdaQueryWrapper<CourseRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseRecord::getCoursePubId, coursePubId);
        queryWrapper.eq(CourseRecord::getCompanyId, companyId);

        List<CourseRecord> recordList = this.list(queryWrapper);

        //3.po转为dto返回
        List<CourseRecordDTO> courseRecordDTOS = CourseRecordConvert.INSTANCE.entitys2dtos(recordList);
        return courseRecordDTOS;
    }
}
